"""Test for transitions"""

import os
import datetime
from time import sleep

from django.test import TestCase
from django.conf import settings

import slots.models as slots_models
from slots.tests.helpers import create_models, destroy_models, \
                                           Header, Page, Sponsor, TimingTest

class TransitionsTest(TimingTest):
    def create_transition(self, header, start):
        "Relates the given header to self.page starting at ``start``"
        return slots_models.Transition.objects.create_transition(self.page,
                                                          header, start)
    def create_transition_in_five_seconds_time(self, header):
        transition = self.create_transition(header,
                                            self.five_seconds_time)
        return transition
    def create_transition_in_ten_seconds_time(self, header):
        transition = self.create_transition(header,
                                            self.five_seconds_time + self.five_seconds)
        return transition
    def testTransitionCreationWorks(self):
        "Does creating Transitions work?"
        self.assertEqual(slots_models.Transition.objects.all().count(),0)
        self.create_transition_in_five_seconds_time(self.header1)
        self.assertEqual(slots_models.Transition.objects.all().count(),1)
    def testQueryingAllTransitionsForAnObject(self):
        "Does querying for all Transitions against an object work?"
        transition = self.create_transition_in_five_seconds_time(self.header1)
        # now see if we can get back what we want
        timeline = slots_models.Transition.objects.get_for_object(self.page)
        # we expect a dictionary
        self.assert_(type(timeline),type({}))
        # it should have a key of 'header'
        self.assert_(timeline.has_key('header'))
        # header should have a value that's a query set, so we'll cast it to a
        # list and see if it contains our single transition
        self.assertEqual(list(timeline['header']),[transition])
        # and the transition object should have a referring_object which is
        # self.header1.  check transition, since we've already asserted that
        # it's the same as what's in the dictionary
        self.assertEqual(transition.referring_object, self.header1)
        # and it should refer to our page
        self.assertEqual(transition.referenced_object, self.page)
    def testQueryingTransitionsByTypeForAnObject(self):
        "Does querying for Transitions of a type against an object work?"
        transition = self.create_transition_in_five_seconds_time(self.header1)
        # this returns a queryset of transition objects based on the content
        # type of self.header1
        timeline = slots_models.Transition.objects.get_for_type_against_object(
                                                             self.header1,
                                                             self.page)
        # since we've only one, let's see what we've got
        self.assertEqual(timeline[0], transition)
    def testCurrentOfTypeForObject(self):
        "Does asking for the 'current' object matching a type work?"
        transition = self.create_transition_in_five_seconds_time(self.header1)
        # the call says "give me the current transition where the relationship
        # is one where the referrng object is a header, and it's referring to
        # this exact page
        #
        # we sleep for 6 seconds to make sure we've gone past the change
        sleep(6)
        current = slots_models.Transition.objects.current_of_type_for_object(
                                                                self.header1,
                                                                self.page)
        # just make sure we get it back
        self.assertEqual(current, transition)
    def testCurrentChangesAccordingToTransitions(self):
        "Does 'current' return diffrent things according to the Transitions?"
        transition1 = self.create_transition_in_five_seconds_time(self.header1)
        transition2 = self.create_transition_in_ten_seconds_time(self.header2)
        # now, go to sleep, and wake up when we expect it to be there
        sleep(6)
        current = slots_models.Transition.objects.current_of_type_for_object(
                                                                self.header1,
                                                                self.page)
        # just make sure we get it back
        self.assertEqual(current, transition1)
        # back to sleep
        sleep(5)
        # wake up! same call - first argument is used to represent the _type_ of
        # object we care about
        current = slots_models.Transition.objects.current_of_type_for_object(
                                                                self.header1,
                                                                self.page)
        # and we're now expecting header2
        self.assertEqual(current, transition2)
    def testNextAndPreviousTransitions(self):
        "Do the 'next' and 'previous' properties work?"
        transition1 = self.create_transition_in_five_seconds_time(self.header1)
        transition2 = self.create_transition_in_ten_seconds_time(self.header2)
        # these are easy: transition1's next is transition2, and
        # therefore 2's previous is 1
        self.assertEqual(transition1.next,transition2)
        self.assertEqual(transition2.previous,transition1)
        # these methods just call the other ones anyway, but, meh.  free
        # coverage!  NB we have to do the microsecond nonsense to flatten the
        # timestamps.  annoying.
        self.assertEqual(transition1.next_change.replace(microsecond=0),
                         transition2.change_time.replace(microsecond=0))
        self.assertEqual(transition2.previous_change.replace(microsecond=0),
                         transition1.change_time.replace(microsecond=0))
    def testSchedulingChangeViaInstance(self):
        "Can we create a new transition using an existing one?"
        transition = self.create_transition(self.header1,
                                            datetime.datetime.now())
        # this call makes a new transition against the same referenced object as
        # the existing one. read 'schedule_change' with the verb form of
        # 'schedule'
        new_transition = transition.schedule_change(self.header2,
                                                    self.five_seconds_time)
        # make sure the new transition still refers to the page
        self.assertEqual(new_transition.referenced_object, self.page)
        # now wait 5 seconds and see if current does its job
        sleep(5)
        # self.header1 is just a representative object.  we could pass in Header
        # here!
        current = slots_models.Transition.objects.current_of_type_for_object(
                                                                self.header1,
                                                                self.page)
        # and we're now expecting header2
        self.assertEqual(current, new_transition)
    def testSchedulingDifferentTypeViaInstanceFails(self):
        "Does scheduling a change fail if the referring object type differs?"
        transition = self.create_transition(self.header1,
                                            datetime.datetime.now())
        self.assertRaises(ValueError,
                          lambda:transition.schedule_change(
                              self.sponsor, self.five_seconds_time
                          ))
